// =============================================================
// CFactory/CService/CServiceProxy/CServiceContainer
// ---------------------------------------
// Author : Woo-Hyun Kim
// Email : woorung@icu.ac.kr or woorung@nhncorp.com
// Date : Aug. 24, 2007
// =============================================================
#include "CService.h"

//------------------------------------------------------------------------
// User Service
//------------------------------------------------------------------------
long CService::id = 0;

CService::CService()
{
	soap = NULL;

        char tmp_name[32];
        sprintf(tmp_name,"Service-%ld", id++);

	this->name = tmp_name;
	this->iname = tmp_name;
}

CService::CService(char *name)
{
	soap = NULL;

	this->name = name;
	this->iname = name;
}

// copy constructor
CService::CService(const CService &rhs)
{
#ifdef DEBUG
cout << "[CService] copy" << endl;
#endif
	soap = NULL;

	this->name = rhs.getName();
	this->iname = rhs.instance();
}

CService::~CService()
{
}

// clone
CService *CService::clone() const
{
#ifdef DEBUG
cout << "[CService] clone" << endl;
#endif
	return new CService(*this);
}

CService *CService::newInstance() const
{
#ifdef DEBUG
cout << "[CService] newInstance" << endl;
#endif
	return clone();
}

// assign constructor
CService &CService::operator=(const CService &rhs) 
{
#ifdef DEBUG
cout << "[CService] =" << endl;
#endif

	this->name = rhs.getName();
	this->iname = rhs.instance();

	return *this;
}

// comparison
bool CService::blindlyEquals(const CObject *rhs) const
{
#ifdef DEBUG
cout << "[CService] blindlyEquals" << endl;
#endif
	const CService *casted_rhs = dynamic_cast<const CService *>(rhs);
	if(casted_rhs==NULL) {
#ifdef DEBUG
cout << "[CService] ==================================" << endl;
cout << "[CService] type is not casted" << endl;
#endif

		return false;
	}

	string rhs_name = casted_rhs->getName();
	string rhs_iname = casted_rhs->instance();

	// perform compariosn on private data
#ifdef DEBUG
	cout << "[CService] lhs = [" << name << "], rhs = [" << rhs_name << "]" << endl;
#endif
	bool isEqual = false;



	// both of the service type & instance name must be same
	// ==========================================================
	// ////////////////////////////////////////////////////////// 
	if(name==rhs_name&&iname==rhs_iname) isEqual = true;
	// ////////////////////////////////////////////////////////// 
	// ==========================================================




#ifdef DEBUG
	else { cout << "not equals : " << name << " == " << rhs_name<< endl; }
#endif

	return (isEqual&&CObject::blindlyEquals(rhs));
}

// comparison
const type_info *CService::getTypeEquiv() const
{
#ifdef DEBUG
cout << "[CService] getTypeEquiv" << endl;
cout << "[CService] typeid name = " << typeid(this).name() << endl;
#endif

	return &typeid(this);
}

void CService::setName(char *name)
{
        this->name = name;
	this->iname = name;
}

char *CService::getName() const
{
        return (char *)name.c_str();
}

void CService::instance(char *iname)
{
        this->iname = iname;
}

char *CService::instance() const
{
        return (char *)iname.c_str();
}

// parameterize
int CService::parameterize(cube__CObject *in, map<string,string> &keyval)
{
	CObjectArray *objs = dynamic_cast<CObjectArray *>(in);
	if(objs==NULL) {
#ifdef DEBUG
		cerr << "ERROR : input type must be an array" << endl;
#endif 
		return -1;
	}

#ifdef DEBUG
	cerr << "input params = " << objs->__size << endl;
#endif

	for(int i=0;i<objs->__size;i++) {
		cube__CKeyValue *kv = dynamic_cast<cube__CKeyValue *>(objs->__ptr[i]);
		if(kv==NULL) {
#ifdef DEBUG
			cerr << "ERROR : array must have (key,value) pairs" << endl;
#endif 
			return -2;
		}

		string k = kv->key;
		string v = kv->value;

#ifdef DEBUG
		cerr << "(key,value) = (" << k << "," << v << ")" << endl;
#endif

		keyval[k] = v;
	}

	return objs->__size;
}

// incarnate
int CService::incarnate(struct cube__invokeResponse &res, map<string,string> &keyval)
{
	CObjectArray *pobjs = (CObjectArray *)soap_new_CObjectArray(soap, -1);
	pobjs->__size = keyval.size();
	pobjs->__ptr = (cube__CObject **)soap_malloc(soap, (pobjs->__size)*sizeof(*pobjs->__ptr));

	// sort automatically and make response
	map<string,string>::iterator current = keyval.begin();
	for(int i=0;current!=keyval.end();) {
		pobjs->__ptr[i] = (cube__CKeyValue *)soap_new_cube__CKeyValue(soap, -1);

		char *k = (char *)current->first.c_str();
		char *v = (char *)current->second.c_str();

		dynamic_cast<cube__CKeyValue *>(pobjs->__ptr[i])->set(k,v);

		i++;
		current++;
	}

	res.out = pobjs;

	return keyval.size();
}

// service invocation
void CService::execute(struct soap *soap, cube__CObject *in, struct cube__invokeResponse &res)
{
	this->soap = soap;

	run(in,res);
}

// it must be implemented in real services
void CService::run(cube__CObject *in, struct cube__invokeResponse &res)
{
	cout << "[" << name << "]user-defined service interface must be implemented here." << endl;
}
